import os
import re
import datetime
from functools import reduce

from pathlib import Path
import pandas as pd
from pandas import DataFrame, Series
from datetime import datetime
from pathlib import Path

from common import utils

# 中文字符宽度调整
pd.set_option('display.unicode.east_asian_width', True)
# 显示所有列
pd.set_option('display.max_columns', None)
# 显示所有行
pd.set_option('display.max_rows', None)
# 设置value的显示长度为100，默认为50
pd.set_option('max_colwidth', 100)

BASE_PATH_企业级应用课设 = r"D:\100-Project\2024-2025-2学期安排\武昌首义学院\19201116_《企业级应用开发课程设计（企业）》"

# 形如：20211119003-闵鑫杰.mp4
PATTERN_视频 = r'^([^-.]+)-([^-.]+)\.([^-.]+)$'

# 形如：《企业级应用开发课程设计（企业）》报告-20211119003-闵鑫杰.0619.0619.docx
PATTERN_报告 = r'^([^-.]+)-([^-.]+)-([^-\.]+)\.([^-\.]+)\.([^-.]+)\.([^-\.]+)$'


def check_报告_filename_format(filename_list):
    return utils.check_filename_format(filename_list, PATTERN_报告)


def check_视频_filename_format(filename_list):
    # pattern = r'^[^-\.]+-[^-\.]+\.[^-\.]+$'
    return utils.check_filename_format(filename_list, PATTERN_视频)


def _get_files_name(folder_path, file_types=['.docx', '.pdf'], return_type="name_only") -> pd.Series:
    """
    获得指定目录下的所有指定类型文件的名称

    参数:
        folder_path: 要搜索的目录路径
        file_types: 要包含的文件扩展名列表 (例如 ['.docx', '.pdf'] 或 ['.mp4'])
        return_type: 返回的文件名格式 ("name_only", "full_path", "relative")

    返回:
        pd.Series: 包含所有匹配文件名的Series
    """
    try:
        # 验证文件夹是否存在
        if not os.path.isdir(folder_path):
            print(f"错误: 文件夹不存在 - {folder_path}")
            return pd.Series([], name='文件名')

        folder = Path(folder_path)
        matched_files = []
        file_types = [ext.lower() for ext in file_types]  # 统一小写处理

        # 收集所有匹配的文件
        for item in folder.iterdir():
            if item.is_file() and item.suffix.lower() in file_types:

                # 根据返回类型处理路径
                if return_type == "name_only":
                    matched_files.append(item.name)
                elif return_type == "full_path":
                    matched_files.append(str(item.absolute()))
                elif return_type == "relative":
                    matched_files.append(str(item.relative_to(folder)))
                else:
                    # 默认返回完整路径
                    matched_files.append(str(item.absolute))

        # 按文件名排序
        matched_files.sort()

        print(f"在 {folder_path} 中找到 {len(matched_files)} 个 {file_types} 文件")

        return pd.Series(matched_files, name='文件名')

    except Exception as e:
        print(f"获取文件列表时出错: {str(e)}")
        return pd.Series([], name='文件名')


def get_报告_files_name(folder_path) -> Series:
    se_报告_file_name = _get_files_name(folder_path, ['.docx', '.pdf'], "name_only")
    if se_报告_file_name:
        check_报告_filename_format(se_报告_file_name)

    return se_报告_file_name


def get_视频_files_name(folder_path) -> Series:
    se_视频_file_name = _get_files_name(folder_path, ['.mp4', '.mkv'], "name_only")
    if len(se_视频_file_name) > 0:
        check_视频_filename_format(se_视频_file_name)
    return se_视频_file_name


def _get_segment_from_filename(
        files_name: pd.Series,
        part_index: int,
        segment_name: str,
        pattern,
        check_duplicates: bool = False
) -> pd.Series:
    extracted = utils.extract_parts_from_series(files_name, part_index, pattern)

    if utils.check_duplicates and utils.find_duplicates(extracted):
        exit(0)

    extracted.name = segment_name
    return extracted


def get_学生_信息() -> DataFrame:
    try:
        # 读取Excel文件中的指定列
        df = pd.read_excel(
            f"{BASE_PATH_企业级应用课设}\\学生名单.xlsx",
            usecols=['学号', '姓名'],  # type: ignore
            dtype={'学号': int, '姓名': str},
            header=0,
        )
        print(f"✅ 成功读取文件: {BASE_PATH_企业级应用课设}\学生名单.xlsx")
        return df

    except Exception as e:
        print(f"❌ 读取失败: {str(e)}")
        raise


def add_year_prefix_enhanced(series: Series, year: str) -> Series:
    # 转换为字符串并验证格式
    str_series = series.astype(str)

    # 检查是否为四位数字
    mask = str_series.str.match(r'^\d{4}$')

    # 添加前缀
    result = year + str_series

    # 标记无效输入
    result[~mask] = "无效格式: " + str_series[~mask]

    return result


# 定义转换函数
def convert_single_date(yyyymmdd):
    try:
        # 提取月份和日期
        year = int(yyyymmdd[:4])
        month = int(yyyymmdd[4:6])
        day = int(yyyymmdd[6:])
        return datetime(year, month, day)
    except (ValueError, TypeError) as e:
        print(f"转换日期格式时出错: {str(e)}")
        # 处理无效格式
        return pd.NaT


def convert_mmdd_to_date(series) -> Series:
    yyyymmdd = add_year_prefix_enhanced(series, "2025")
    se_date = yyyymmdd.apply(convert_single_date)

    # 应用转换函数
    return se_date


def calculate_date_scores(se_date: Series, base_score=25) -> Series:
    """
    计算日期数组中每个日期的评分
    """

    # 1. 找到最早日期
    min_date = se_date.min()

    # 2. 计算每个日期与最早日期的天数差
    days_diff = (se_date - min_date).dt.days

    return base_score - (days_diff + 1) // 2


def merge_student_dataframes(*dfs):
    """
    合并多个包含学生数据的DataFrame

    参数:
    *dfs : 可变数量的DataFrame，每个DataFrame必须包含'学号'和'姓名'列

    返回:
    pd.DataFrame : 合并后的DataFrame，包含学号、姓名和所有科目列

    异常:
    ValueError: 如果输入少于两个DataFrame
    """
    if len(dfs) < 2:
        raise ValueError("至少需要两个DataFrame进行合并")

    # 1. 提取所有DataFrame中的科目列（排除学号和姓名）
    all_subject_columns = set()
    for df in dfs[1:]:  # 从第二个DataFrame开始
        subject_cols = [col for col in df.columns if col not in ['学号', '姓名']]
        all_subject_columns.update(subject_cols)

    # 2. 创建基础表（只保留学号和姓名）
    base_df = dfs[0][['学号', '姓名']].copy()

    # 3. 使用reduce函数逐步合并所有DataFrame
    def merge_func(left, right):
        # 从右侧DataFrame中提取学号和科目列
        right_subject_cols = [col for col in right.columns if col in all_subject_columns]
        right_subset = right[['学号'] + right_subject_cols]
        right_subset['学号'].astype(int)

        # 左连接合并
        return pd.merge(left, right_subset, on='学号', how='left')

    # 应用reduce进行逐步合并
    merged_df = reduce(merge_func, [base_df] + list(dfs[1:]))

    return merged_df


if __name__ == "__main__":
    se_files_name = get_报告_files_name(f"{BASE_PATH_企业级应用课设}\提交\报告")
    print(se_files_name)
